#pragma once

#include "simd.h"
//WARNING:
//math.h and glm.hpp have to be in this particular order
//if not in this specific order, massive amounts of weird errors occur
#include "math.h"
#include "glm/glm.hpp"
#include "util.h"

using namespace glm;

struct RayStream : public Stream
{
	RayStream(int p_block_capacity) 
		: origins(p_block_capacity), directions(p_block_capacity), Stream(p_block_capacity)
	{
	}
	v3stream origins;
	v3stream directions;
};

struct RayIntersectionStream : public Stream
{
	RayIntersectionStream(int p_block_capacity) 
		: position(p_block_capacity), surface_normal(p_block_capacity),
		intersects(p_block_capacity), Stream(p_block_capacity)
	{
	}
	f32stream intersects;
	v3stream position;
	v3stream surface_normal;
};
struct GenerateEyeRaysInfo
{
	in struct 
	{	
		int min; 
		int max; 
	} y_bounds;
	in vec3 delta_position_per_pixel;
	in vec3 eye_position;
	in Frustrum frustrum;
	in View rays_view;

	out RayStream* __restrict rays;
};

//generate eye rays for y0 -> y1, 0 -> width
//stores it into rays
inline void generate_eye_rays(GenerateEyeRaysInfo info)
{
	v3block delta_position_per_pixel = as_v3block(info.delta_position_per_pixel);
	v3block frustrum_top_left = as_v3block(info.frustrum.top_left_position);
	v3block eye_position = as_v3block(info.eye_position);

	//int current_block = info.ray_stream_offset;

	v3stream origins = info.rays->origins;
	v3stream directions = info.rays->directions;

	int blocks_per_row = info.rays->blocks_per_row;
	for(int y = info.y_bounds.min; y < info.y_bounds.max; y++)
	{
		f32block x_pixel_base = as_f32block(0.0);
		f32block y_pixel = as_f32block((float)y);
				
		for(int block = 0; block < blocks_per_row; block+=1)
		{
			f32block x_pixel = x_pixel_base + simd::c_increasing;
			x_pixel_base = x_pixel_base + simd::c_8;

			v3block pixel_position = as_v3block(x_pixel, y_pixel, simd::c_0);

			v3block world_position = pixel_position * delta_position_per_pixel
				+ frustrum_top_left;		
			int block_index = (y - info.y_bounds.min) * blocks_per_row + block;
			origins.set_block(block_index, world_position);
			v3block world_direction = world_position - eye_position;			
			f32block invmag = inv_mag(world_direction);
			
			directions.set_block(block_index, world_direction * invmag);		

		}
	}
}